/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 *
 * This file is part of Indigo toolkit.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

package com.indigo;

import java.io.IOException;
import java.io.FileOutputStream;
import java.io.File;

public class Cano
{
   public Cano (String path) throws Exception
   {
      path = path + File.separator + _dllpath;

      String fullpath = path;
      try
      {
         fullpath = (new File(path)).getCanonicalPath();
      }
      catch (Exception e)
      {
      }

      if (_os == OS_LINUX)
         System.load(fullpath + File.separator + "libcanojni.so");
      else if (_os == OS_MACOS)
         System.load(fullpath + File.separator + "libcanojni.dylib");
      else // _os == OS_WINDOWS
         System.load(fullpath + File.separator + "canojni.dll");

      _sid = allocSessionId();
   }

   public Cano () throws Exception
   {
      this("lib");
   }

   @Override
   protected void finalize () throws Throwable
   {
      releaseSessionId(_sid);
   }
   
   public native String getVersion () throws Exception;
   public native String getCanonicalSmiles (String molecule, String options) throws Exception; 
   public native String getLayeredCode (String molecule, String options) throws Exception;

   public String getLayeredCode (String molecule) throws Exception
   {
      return getLayeredCode(molecule, null);
   }

   public String getCanonicalSmiles (String molecule) throws Exception
   {
      return getCanonicalSmiles(molecule, null);
   }

   private static native long allocSessionId ();
   private static native void releaseSessionId (long id);

   private long _sid;

   ////////////////////////////////////////////////////////////////
   // INITIALIZATION
   ////////////////////////////////////////////////////////////////
   private static final int OS_WINDOWS = 1;
   private static final int OS_MACOS = 2;
   private static final int OS_LINUX = 3;
   private static final int X86 = 32;
   private static final int X64 = 64;
   private static int _arch = 0;
   private static int _os = 0;
   private static String _dllpath = "";

   private static int getArch ()
   {
       String archstr = System.getProperty("os.arch");
       if (archstr.equals("x86") || archstr.equals("i386"))
           return X86;
       else if (archstr.equals("x86_64") || archstr.equals("amd64"))
           return X64;
       else
           throw new Error("Platform not unrecognized");
   }

   private static int getOs ()
   {
      String namestr = System.getProperty("os.name");
       if (namestr.matches("^Windows.*"))
           return OS_WINDOWS;
       else if (namestr.matches("^Mac OS.*"))
           return OS_MACOS;
       else if (namestr.matches("^Linux.*"))
           return OS_LINUX;
       else
           throw new Error("Operating system not unrecognized");
   }

   private static String getDllPath ()
   {
      String path = "";
      switch (_os)
      {
         case OS_WINDOWS:
            path += "Win";
            break;
         case OS_LINUX:
            path += "Linux";
            break;
         case OS_MACOS:
            path += "Mac";
            break;
         default:
            throw new Error("OS not set");
      }
      path += File.separator;

      if (_os == OS_MACOS)
      {
         String version = System.getProperty("os.version");
         
         if (version.startsWith("10.5"))
            path += "10.5";
         else if (version.startsWith("10.6"))
            path += "10.6";
         else
            throw new Error("OS version not supported");
      } else 
      {
         switch (_arch)
         {
            case X86:
               path += "x86";
               break;
            case X64:
               path += "x64";
               break;
            default:
               throw new Error("Platform not set");
         }
      }

      return path;
   }
   
   static
   {
      _arch = getArch();
      _os = getOs();
      _dllpath = getDllPath();
   }

   ////////////////////////////////////////////////////////////////
   // TEST CODE
   ////////////////////////////////////////////////////////////////
   public static void main(String[] args) throws IOException
   {
      try
      {
         Cano cano = new Cano();
      
         System.out.println(cano.getVersion());
         System.out.println(cano.getCanonicalSmiles("C1C=CC=CC=1", null));
         System.out.println(cano.getCanonicalSmiles("NC1C=C(Br)C=CC=1", ""));
         System.out.println(cano.getCanonicalSmiles("NC1C=C(Br)C=CC=1", "-AROMATICITY"));
         System.out.println(cano.getCanonicalSmiles("N1(C(SCC1C(=O)N[C@@H](CCO)C)C1CC2CCC1C2)C(CN(CC)C)=O |a:8|"));
         System.out.println(cano.getLayeredCode("NC1C=C(Br)C=CC=1"));
         System.out.println(cano.getLayeredCode("C[C@@H]1CC(C(=O)N1)1N2CC(C)3CN1CC(C)(C2)C3=O", "-CISTRANS")); 
      }
      catch (Exception e)
      {
         System.out.println(e.getMessage());
      }
      //System.out.println(cano.getInChI("C1C=CC=CC=1"));
   }
}
